#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <cerrno>
#include <functional>
#include <unordered_map>
#include "Log.hpp"
#include "nocopy.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"
#include "Common.hpp"

// tcp服务器会接受很多连接 上面我们提到完整报文的问题 要想解决这个问题 需要把之前的数据保留
// 一个链接对应一个文件描述符 需要给每个fd创建配对的发送/接收缓冲区

class TcpConnection;
class TcpServer;

uint32_t ET_EVENT_IN = (EPOLLIN | EPOLLET);
uint32_t ET_EVENT_OUT = (EPOLLOUT | EPOLLET);
const static int g_buffer_size = 128;

using func_t = std::function<void(std::weak_ptr<TcpConnection>)>;
using except_func = std::function<void(std::weak_ptr<TcpConnection>)>;

// Tcp连接类 一个连接有: fd 收发缓冲区 对端ip+port 网络操作回调函数
class TcpConnection
{
private:
    int _sockFd;
    std::string _inbuffer; // string无法处理二进制流 vector可以
    std::string _outbuffer;

public:
    std::string _clientIp;
    uint16_t _clientPort;

    func_t _recv_cb;
    func_t _send_cb;
    except_func _except_cb;

    // 回指指针：tcp连接通过该指针 调用tcp服务器接口
    std::weak_ptr<TcpServer> _tcpSvr_weakPtr;

public:
    TcpConnection(int sockFd)
        : _sockFd(sockFd)
    {
    }

    void SetHandler(func_t recv_cb, func_t send_cb, except_func except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

    int getSockFd()
    {
        return _sockFd;
    }

    std::string &getInbuffer()
    {
        return _inbuffer;
    }

    std::string &getOutBuffer()
    {
        return _outbuffer;
    }

    void AppendInBuffer(const std::string &info)
    {
        _inbuffer += info;
    }

    void AppendOutBuffer(const std::string &info)
    {
        _outbuffer += info;
    }

    void SetTcpSvr_weakPtr(std::weak_ptr<TcpServer> tcpSvr_ptr)
    {
        _tcpSvr_weakPtr = tcpSvr_ptr;
    }

    void ClearInBuffer()
    {
        _inbuffer.clear(); // 清空接收缓冲区
    }

    ~TcpConnection()
    {
    }
};

class TcpServer : public std::enable_shared_from_this<TcpServer>, public nocopy
{
    static const int num = 64;

private:
    std::shared_ptr<Epoller> _epoller_ptr; // 内核
    std::shared_ptr<Sock> _listensock_ptr; // 监听socket 可以把他移除到外部
    std::unordered_map<int, std::shared_ptr<TcpConnection>> _tcpConnections;
    struct epoll_event revs[num];
    uint16_t _tcpPort;
    func_t _MsgHandler; // 处理CS之间数据的函数 由主函数传入
    bool _quit;

public:
    TcpServer(uint16_t port, func_t MsgHandler)
        : _epoller_ptr(new Epoller()),
          _listensock_ptr(new Sock()),
          _tcpPort(port),
          _MsgHandler(MsgHandler),
          _quit(true)
    {
    }

    // socket bind listen
    void Init()
    {
        // 1.建立连接 绑定端口号 处于监听状态
        _listensock_ptr->Socket();
        int fd = _listensock_ptr->getSocketFd();
        SetNonBlockOrDie(fd);
        _listensock_ptr->Bind(_tcpPort);
        _listensock_ptr->Listen();
        lg(Info, "create listen socket success: %d", fd);

        // 2.将监听套接字设置进epoll模型 监听套接字只用处理read事件
        auto AccepterBind = std::bind(&TcpServer::Accepter, this, std::placeholders::_1);
        AddConnection(fd, ET_EVENT_IN, AccepterBind, nullptr, nullptr);

        // 将类内成员函数转换为function对象传参 TcpServer::Accepter单独传不过去
        // 不存在"void (weak_ptr<Conn> conn)"-->"function<void (weak_ptr<Conn>)>" 适当构造函数
        // void Accepter(weak_ptr<Connection> connWeakPtr)
        // AddConnection(fd, ET_EVENT_IN, TcpServer::Accepter, nullptr, nullptr);
    }

    /*
    class TcpConnection
    {
        int _sockFd;
        std::string _inbuffer;
        std::string _outbuffer;
        func_t _recv_cb;
        func_t _send_cb;
        except_func _except_cb;
        std::string _clientIp;
        uint16_t _clientPort;
        std::weak_ptr<TcpServer> _tcpSvr_WeakPtr;
    };
    */
    // using func_t = std::function<void (std::weak_ptr<Connection>)>
    void AddConnection(int sockFd, uint32_t event, func_t recv_cb, func_t send_cb, except_func except_cb,
                       const std::string &ip = "0.0.0.0", uint16_t port = 0)
    {
        // 1. 给sockFd添加一条连接
        auto new_connection = std::make_shared<TcpConnection>(sockFd);
        new_connection->SetTcpSvr_weakPtr(shared_from_this());
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->_clientIp = ip;
        new_connection->_clientPort = port;

        // 2. 添加到unordered_map {fd : tcpConnection}
        _tcpConnections.insert(std::make_pair(sockFd, new_connection));

        // 3. 添加fd及其对应的事件到内核中
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD, sockFd, event);

        lg(Debug, "add a new connection success, sockfd is : %d", sockFd);
    }

    void Loop()
    {
        _quit = false;

        while (!_quit)
        {
            Dispatcher(-1); // Dispatcher(3000);
            // PrintConnection();
        }

        _quit = true;
    }

    void Dispatcher(int timeout)
    {
        int n = _epoller_ptr->EpollerWait(revs, num);
        for (int i = 0; i < n; i++)
        {
            uint32_t events = revs[i].events;
            int sockFd = revs[i].data.fd;

            // 统一把事件异常转换成为读写问题 只需要处理EPOLLIN EPOLLOUT
            // if (events & EPOLLERR)
            //     events |= (EPOLLIN | EPOLLOUT);
            // if (events & EPOLLHUP)
            //     events |= (EPOLLIN | EPOLLOUT);

            if ((events & EPOLLIN) && IsConnectionSafe(sockFd))
            {
                std::shared_ptr<TcpConnection> connPtr = _tcpConnections[sockFd];
                if (connPtr->_recv_cb)
                    connPtr->_recv_cb(connPtr);
            }

            if ((events & EPOLLOUT) && IsConnectionSafe(sockFd))
            {
                std::shared_ptr<TcpConnection> connPtr = _tcpConnections[sockFd];
                if (connPtr->_send_cb)
                    connPtr->_send_cb(connPtr);
            }
        }
    }

    void PrintConnection()
    {
        std::cout << "===============show connections begin===============" << std::endl;
        for (auto &connection : _tcpConnections)
        {
            std::cout << std::endl;
            std::cout << "=============per conn=============" << std::endl;
            std::cout << "fd: " << connection.second->getSockFd();
            std::string inbuf = connection.second->getInbuffer();
            std::cout << " inbuffer: " << (inbuf.empty() ? "null" : inbuf) << std::endl;
            std::cout << "=============per conn=============" << std::endl;
            std::cout << std::endl;
        }
        std::cout << "===============show connections end===============" << std::endl;
    }

    bool IsConnectionSafe(int fd)
    {
        auto iter = _tcpConnections.find(fd);
        if (iter == _tcpConnections.end())
            return false;
        else
            return true;
    }

    // 链接管理器
    void Accepter(std::weak_ptr<TcpConnection> connectionWeakPtr)
    {
        auto connSharedPtr = connectionWeakPtr.lock(); // 锁定一次共享指针
        if (!connSharedPtr)
            return; // 如果连接对象失效，直接返回

        while (true)
        {
            auto listenSockFd = std::make_shared<Sock>(connSharedPtr->getSockFd());
            std::string clientip;
            uint16_t clientport;

            // 接受连接
            int serverSockFd = listenSockFd->Accept(&clientip, &clientport);

            if (serverSockFd > 0)
            {
                lg(Debug, "New client [%s:%d], sockfd: %d", clientip.c_str(), clientport, serverSockFd);

                // 设置服务器套接字为非阻塞
                SetNonBlockOrDie(serverSockFd);

                // 添加新的连接到事件循环
                AddConnection(serverSockFd, ET_EVENT_IN,
                              std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1),
                              clientip, clientport);
            }
            else
            {
                // 错误处理：EWOULDBLOCK 和 EINTR
                if (errno == EWOULDBLOCK)
                {
                    lg(Info, "Accept operation would block. No new connection at the moment.");
                    break; // 当前没有新的连接，退出循环
                }
                else if (errno == EINTR)
                {
                    lg(Warning, "Accept operation interrupted by signal. Retrying...");
                    continue; // 系统调用被信号中断，继续尝试接受连接
                }
                else
                {
                    lg(Warning, "Accept failed with error code %d, errno: %d", serverSockFd, errno);
                    break; // 其他错误，退出循环
                }
            }
        }
    }

    // 事件管理器不用关心数据的格式 数据完整性/报文格式等由协议管理
    // 从网络读取数据到接收缓冲区
    void Recver(std::weak_ptr<TcpConnection> connectionWeakPtr)
    {
        if (connectionWeakPtr.expired())
            return;
        auto connSharedPtr = connectionWeakPtr.lock();

        int fd = connSharedPtr->getSockFd();
        while (true)
        {
            char buffer[g_buffer_size];
            memset(buffer, 0, sizeof(buffer));
            ssize_t n = recv(fd, buffer, sizeof(buffer) - 1, 0); // 0: 默认选项
            if (n > 0)
            {
                // 成功接收数据，追加到接收缓冲区
                connSharedPtr->AppendInBuffer(buffer);
            }
            else if (n == 0)
            {
                // 连接被对方关闭
                lg(Info, "sockfd: %d, client info [%s:%d] quit...", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);
                connSharedPtr->_except_cb(connSharedPtr); // 调用异常回调处理连接关闭
                return;
            }
            else
            {
                // 读取失败，检查 errno
                if (errno == EWOULDBLOCK)
                {
                    // 套接字缓冲区为空，当前没有数据可读
                    lg(Warning, "sockfd: %d, client info %s:%d no data available to read...", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);
                    break; // 暂停读取，等待下一次可读事件
                }
                else if (errno == EINTR)
                {
                    // 被信号中断，继续尝试读取
                    lg(Warning, "sockfd: %d, client info %s:%d recv interrupted by signal...", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);
                    continue;
                }
                else
                {
                    // 发生其他错误，调用异常回调
                    lg(Warning, "sockfd: %d, client info %s:%d recv error, errno: %d", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort, errno);
                    connSharedPtr->_except_cb(connSharedPtr); // 调用异常回调处理错误
                    return;
                }
            }
        }

        // 数据接收完毕，交给业务层处理
        _MsgHandler(connSharedPtr);
    }

    // 把发送缓冲区中的数据发送到网络
    void Sender(std::weak_ptr<TcpConnection> connectionWeakPtr)
    {
        if (connectionWeakPtr.expired())
            return;
        auto connSharedPtr = connectionWeakPtr.lock();

        int fd = connSharedPtr->getSockFd();
        auto &outbuffer = connSharedPtr->getOutBuffer();
        while (true)
        {
            ssize_t n = send(fd, outbuffer.c_str(), outbuffer.size(), 0);
            if (n > 0)
            {
                outbuffer.erase(0, n);
                if (outbuffer.empty())
                    break;
            }
            else if (n == 0)
            {
                // 对方已经关闭连接
                lg(Info, "sockfd: %d, client info %s:%d closed connection...", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);
                connSharedPtr->_except_cb(connSharedPtr); // 调用异常回调处理连接关闭
                return;
            }
            else
            {
                // 发送失败，检查 errno
                if (errno == EWOULDBLOCK)
                {
                    // 发送缓冲区已满 无法继续发送
                    lg(Warning, "sockfd: %d, client info %s:%d send buffer is full...", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);
                    break;
                }
                else if (errno == EINTR)
                {
                    // 被信号中断，继续尝试发送
                    lg(Warning, "sockfd: %d, client info %s:%d send interrupted by signal...", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);
                    continue;
                }
                else
                {
                    lg(Warning, "sockfd: %d, client info %s:%d send error...", fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);
                    connSharedPtr->_except_cb(connSharedPtr);
                    return;
                }
            }
        }

        // 开启对写事件的关心
        if (!outbuffer.empty())
            EnableEvent(fd, true, true);
        // 关闭对写事件的关心
        else
            EnableEvent(fd, true, false);
    }

    void Excepter(std::weak_ptr<TcpConnection> connectionWeakPtr)
    {
        if (connectionWeakPtr.expired())
            return;
        auto connSharedPtr = connectionWeakPtr.lock();

        int fd = connSharedPtr->getSockFd();
        lg(Warning, "Excepter deal sockfd: %d, client info %s:%d",
           fd, connSharedPtr->_clientIp.c_str(), connSharedPtr->_clientPort);

        // 1. 移除对特定fd的关心
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);

        // 2. 从unordered_map中移除
        lg(Debug, "remove %d from _connections...\n", fd);
        _tcpConnections.erase(fd);

        // 3. 关闭异常的文件描述符
        lg(Debug, "close %d done...\n", fd);
        close(fd);
    }

    void EnableEvent(int sockFd, bool readable, bool writeable)
    {
        uint32_t events = 0;
        events |= ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_MOD, sockFd, events);
    }

    ~TcpServer()
    {
    }
};